import Foundation
import SwiftUI
import AVFoundation

class EANScanner: NSObject, ObservableObject, AVCaptureMetadataOutputObjectsDelegate {
    @Published var lastEANCode: String = ""
    
    var scanSession:AVCaptureSession!
    var previewLayer: AVCaptureVideoPreviewLayer?
    
    var scanPermission = 0
    
    // 检查权限
    func checkPermissions() {
        switch AVCaptureDevice.authorizationStatus(for: .video) {
        case .authorized:
            self.prepareScan()
            self.scanPermission = 1
        case .notDetermined:
            AVCaptureDevice.requestAccess(for: .video) { granted in
                if granted {
                    DispatchQueue.main.async {
                        self.prepareScan()
                        self.scanPermission = 1
                    }
                }else{
                    self.scanPermission = 2
                }
            }
        case .denied, .restricted:
            showPermissionDeniedAlert()
        @unknown default:
            fatalError("相机状态未知")
        }
    }
    
    // 准备扫描
    func prepareScan() {
        do {
            self.scanSession = AVCaptureSession()
            self.previewLayer = AVCaptureVideoPreviewLayer(session: self.scanSession)
            self.previewLayer?.videoGravity = .resizeAspectFill
            
            guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return }
            let videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
            if (self.scanSession.canAddInput(videoInput)) {
                self.scanSession.addInput(videoInput)
            } else {
                return
            }
            
            let metadataOutput = AVCaptureMetadataOutput()
            if (self.scanSession.canAddOutput(metadataOutput)) {
                self.scanSession.addOutput(metadataOutput)
                
                metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
                // EAN-13为常见的书本商品条码
                metadataOutput.metadataObjectTypes = [.ean13]
            } else {
                fatalError("元数据添加失败")
            }
            
        } catch {
            fatalError("加载摄像头失败")
        }
    }
    
    // 未批准权限发出提醒
    func showPermissionDeniedAlert() {
        guard let rootViewController = UIApplication.shared.windows.filter({$0.isKeyWindow}).first?.rootViewController else {
            return
        }
        let alertController = UIAlertController(title: "未授予相机权限",
                                                message: "扫描条码需要使用摄像头。请在设置-隐私中启用",
                                                preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "取消", style: .default) {_ in
            self.scanPermission = 2
        })
        alertController.addAction(UIAlertAction(title: "前往设置", style: .default) { _ in
            if let settingsUrl = URL(string: UIApplication.openSettingsURLString) {
                if UIApplication.shared.canOpenURL(settingsUrl) {
                    UIApplication.shared.open(settingsUrl)
                }
            }
        })
        rootViewController.present(alertController, animated: true, completion: nil)
    }
    
    // 处理输出
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        self.scanSession.stopRunning()
        
        if let metadataObject = metadataObjects.first {
            guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }
            guard let stringValue = readableObject.stringValue else { return }
            lastEANCode = stringValue
        }
    }
}

struct EANScannerView: UIViewRepresentable {
    @StateObject var scanner: EANScanner
    
    func makeUIView(context: Context) ->  UIView {
        let view = UIView(frame: CGRect.zero)
        
        DispatchQueue.main.async {
            self.scanner.checkPermissions()
            if let previewLayer = self.scanner.previewLayer {
                previewLayer.frame = view.layer.bounds
                view.layer.addSublayer(previewLayer)
            }
            
            if(self.scanner.scanPermission == 1){
                self.scanner.scanSession.startRunning()
            }
        }
        return view
    }
    
    func updateUIView(_ view: UIView, context: Context) {
        if let previewLayer = scanner.previewLayer {
            previewLayer.frame = view.layer.bounds
        }
    }
}
